package rhc.common.util;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;

/**
 * 多个任务并发执行工具类
 * 
 * @author rhc
 *
 */
public class MultiTaskUtil {

	/**
	 * 任务名和任务列表
	 */
	private static final Map<String, List<Runnable>> TASKNAME_TASKLIST = new ConcurrentHashMap<String, List<Runnable>>();

	/**
	 * 任务名并发数
	 */
	private static final Map<String, Integer> TASKNAME_ASYNCCOUNT = new ConcurrentHashMap<String, Integer>();

	/**
	 * 任务名信号
	 */
	private static final Map<String, Semaphore> TASKNAME_SEMAPHORE = new ConcurrentHashMap<String, Semaphore>();

	/**
	 * 检测评论内容敏感词
	 */
	public static final String CHECK_SENSITIVE_WORDS = "CHECK_SENSITIVE_WORDS";

	static {
		// 注册任务
		try {
			registerTask(CHECK_SENSITIVE_WORDS, 10);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 注册一个任务，并设置并发数
	 * 
	 * @param taskName
	 * @param asyncCount
	 * @throws Exception
	 */
	public static void registerTask(String taskName, int asyncCount) throws Exception {
		if (TASKNAME_ASYNCCOUNT.containsKey(taskName)) {
			throw new Exception("并发任务名 " + taskName + " 已经注册");
		}

		if (asyncCount < 1) {
			throw new IllegalArgumentException("并发任务数必须大于0");
		}

		synchronized (TASKNAME_ASYNCCOUNT) {
			if (TASKNAME_ASYNCCOUNT.containsKey(taskName)) {
				throw new Exception("并发任务名 " + taskName + " 已经注册");
			}
			TASKNAME_ASYNCCOUNT.put(taskName, asyncCount);
			Semaphore semaphore = new Semaphore(asyncCount);
			TASKNAME_SEMAPHORE.put(taskName, semaphore);
		}
	}

	/**
	 * 给一个任务名增加一个并行任务
	 * 
	 * @param taskName
	 * @param runnable
	 * @throws Exception
	 */
	public static void addTask(String taskName, Runnable runnable) throws Exception {
		taskIsExists(taskName);
		NullUtil.objectsIsNull(true, runnable);

		Semaphore taskSemaphore = TASKNAME_SEMAPHORE.get(taskName);

		synchronized (taskSemaphore) {
			List<Runnable> taskList = TASKNAME_TASKLIST.get(taskName);
			if (null == taskList) {
				taskList = new LinkedList<Runnable>();
				TASKNAME_TASKLIST.put(taskName, taskList);
			}
			taskList.add(runnable);
		}
	}

	/**
	 * 启动一个并发任务，如果任务正在运行则退出
	 * 
	 * @param taskName
	 * @throws Exception
	 */
	public static void fireTask(String taskName) throws Exception {
		taskIsExists(taskName);

		final Semaphore taskSemaphore = TASKNAME_SEMAPHORE.get(taskName);

		int asyncCount = TASKNAME_ASYNCCOUNT.get(taskName);
		final List<Runnable> taskList = TASKNAME_TASKLIST.get(taskName);
		if (null != taskList && !taskList.isEmpty() && asyncCount == taskSemaphore.availablePermits()) {

			synchronized (taskSemaphore) {
				if (null != taskList && !taskList.isEmpty() && asyncCount == taskSemaphore.availablePermits()) {
					AsyncTaskUtil.async(null, new Runnable() {

						@Override
						public void run() {

							while (true) {

								try {
									Runnable runnable = taskList.remove(0);
									if (null == runnable) {
										break;
									}
									AsyncTaskUtil.async(taskSemaphore, runnable);
								} catch (Exception e) {
									break;
								}

							}

						}

					});
				}
			}
		}
	}

	/**
	 * 检测任务是否存在
	 * 
	 * @param taskName
	 * @throws Exception
	 */
	private static void taskIsExists(String taskName) throws Exception {
		NullUtil.objectsIsNull(true, taskName);
		if (!TASKNAME_ASYNCCOUNT.containsKey(taskName)) {
			throw new Exception("并发任务名 " + taskName + " 未注册");
		}
	}
}
